package com.ruoyi.project.purchase.service.impl;

import java.util.Date;
import java.util.List;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.project.purchase.domain.RyDepotDetail;
import com.ruoyi.project.purchase.domain.RyDepotHead;
import com.ruoyi.project.purchase.domain.RyPurchaseIn;
import com.ruoyi.project.purchase.domain.pojo.DepotDetailBean;
import com.ruoyi.project.purchase.domain.pojo.DepotHeadItem;
import com.ruoyi.project.purchase.domain.pojo.ParamBean;
import com.ruoyi.project.purchase.mapper.RyDepotDetailMapper;
import com.ruoyi.project.purchase.mapper.RyDepotHeadMapper;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.warehouse.domain.OutRyDepotItem;
import com.ruoyi.project.warehouse.domain.RyDepot;
import com.ruoyi.project.warehouse.domain.RyDepotItem;
import com.ruoyi.project.warehouse.domain.RyInventoryCurrentStock;
import com.ruoyi.project.warehouse.mapper.OutRyDepotItemMapper;
import com.ruoyi.project.warehouse.mapper.RyDepotItemMapper;
import com.ruoyi.project.warehouse.mapper.RyDepotMapper;
import com.ruoyi.project.warehouse.mapper.RyInventoryCurrentStockMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.project.purchase.mapper.RyPurchaseOutMapper;
import com.ruoyi.project.purchase.domain.RyPurchaseOut;
import com.ruoyi.project.purchase.service.IRyPurchaseOutService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 采购出库Service业务层处理
 *
 * @author you
 * @date 2022-09-26
 */
@Service
public class RyPurchaseOutServiceImpl implements IRyPurchaseOutService
{
    @Autowired
    private RyPurchaseOutMapper ryPurchaseOutMapper;

    @Autowired
    private RyDepotHeadMapper ryDepotHeadMapper;

    @Autowired
    private RyDepotDetailMapper ryDepotDetailMapper;

    @Autowired
    private RyDepotMapper ryDepotMapper;

    @Autowired
    private RyDepotItemMapper ryDepotItemMapper;

    @Autowired
    private OutRyDepotItemMapper outRyDepotItemMapper;

    @Autowired
    private RyInventoryCurrentStockMapper ryInventoryCurrentStockMapper;

    /**
     * 查询采购出库
     *
     * @param id 采购出库主键
     * @return 采购出库
     */
    @Override
    public RyPurchaseOut selectRyPurchaseOutById(Long id)
    {
        return ryPurchaseOutMapper.selectRyPurchaseOutById(id);
    }


    /**
     * 新增采购出库
     * 实质上只新增了采购出库主表，子表数据只需要修改相应信息即可
     * 根据主表修改单据子表信息
     * 1.同时需要生成出库记录
     * 2.更改项目库物品当前库存数
     * 3.设置采购总清单出库数量
     */
    @Override
    @Transactional
    public AjaxResult addDepotHeadAndDetail(DepotHeadItem depotHeadItem) {
        //获取用户信息
        SysUser user = SecurityUtils.getLoginUser().getUser();
        //判断是否有子表数据
        List<RyDepotItem> tableData = depotHeadItem.getTableData();
        if(tableData == null || tableData.size() ==0){
            return AjaxResult.error("子表数据不存在");
        }

        //新增采购入库单主表信息
        RyPurchaseOut ryPurchaseOut = new RyPurchaseOut();
        ryPurchaseOut.setNumber(depotHeadItem.getNumber());//单据号
        ryPurchaseOut.setFileName(depotHeadItem.getFileName());
        ryPurchaseOut.setSalesMan(depotHeadItem.getSalesMan());
        ryPurchaseOut.setCreateTime(DateUtils.getNowDate());//创建时间
        ryPurchaseOut.setCreator(user.getUserId());//操作员
        ryPurchaseOut.setRemark(depotHeadItem.getRemark());
        ryPurchaseOut.setStatus("0");
        ryPurchaseOut.setType("出库");
        ryPurchaseOut.setSubType("项目物品");
        ryPurchaseOut.setLinkHeadId(depotHeadItem.getLinkHeadId());//关联项目总清单id

        //判断是否关联了项目总清单
        if(depotHeadItem.getLinkHeadId() != null) {//关联了项目总清单
            ryPurchaseOut.setLinkHeadId(depotHeadItem.getLinkHeadId());//关联采购订单id
            ryPurchaseOut.setLinkNumber(depotHeadItem.getNumber());
            ryPurchaseOut.setProjectHeadId(depotHeadItem.getLinkHeadId());
        }

        /**
         * 统计参数，用于统计明细入库数量
         * 如果totalInNum > 0 存在入库明细，则不需处理
         * 如果totalInNum <= 0 说明明细数据因为条件问题一条都没有入库，
         * 这时就主动抛出错误，使得事务生效，防止主表信息插入而明细表没有数据
         *
         */
        int totalInNum = 0;

        //主表信息入库
        int res = ryPurchaseOutMapper.insertRyPurchaseOut(ryPurchaseOut);
        if(res > 0){
            /**
             * 遍历明细数据，更新单据明细数据
             * 1.生成相应出库记录
             * 2.更改项目库物品当前库存数
             */
            for(RyDepotItem ryDepotItem : tableData){

                ryDepotItem.setHeaderId(ryPurchaseOut.getId());//设置刚生成的项目物品出库单id
                ryDepotItem.setHeaderType("1");//1代表出库数据
                ryDepotItem.setOperTime(new Date());
                ryDepotItem.setUpdateTime(new Date());

                //如果总入库数量为0或是为null,或是操作数量operNumber为0或者为null，则跳过此次循环，不进行出库操作
                if(ryDepotItem.getOperNumber() == null || ryDepotItem.getOperNumber() == 0){
                    continue;
                }

                //如果出库仓库不存在，则跳过此次循环，不进行出库操作
                if(ryDepotItem.getDepotId() == null){
                    continue;
                }

                //获取仓库id和商品id
                Long depotId = ryDepotItem.getDepotId();
                Long inventoryId = ryDepotItem.getInventoryId();
                RyInventoryCurrentStock paramstock = new RyInventoryCurrentStock();
                paramstock.setDepotId(depotId);
                paramstock.setInventoryId(inventoryId);

                //根据depotId和InventoryId查询出当前库存信息
                RyInventoryCurrentStock result = ryInventoryCurrentStockMapper.getCurrentStockByDepotInventId(paramstock);
                System.out.println("--> result:"+result);

                //创建参数对象
                RyInventoryCurrentStock param = new RyInventoryCurrentStock();
                //计算需要更改的总库数量
                //获取原库存数
                Double oldNum = result.getCurrentNumber();
                //获取新出库数量
                Double outNum = ryDepotItem.getOperNumber();
                //需要更改的数量
                Double updateNum = oldNum - outNum;
                param.setCurrentNumber(updateNum);

                //执行修改语句，修改库存数量，根据id修改
                param.setId(result.getId());
                ryInventoryCurrentStockMapper.updateRyInventoryCurrentStock(param);

                //执行明细新增
                ryDepotItemMapper.insertRyDepotItem(ryDepotItem);
                totalInNum += 1;
            }
        }
        //如果统计结果小于等于0,则主动抛出异常
        if(totalInNum <= 0){
//            System.out.println("应主动抛出异常,稍后完善");
            throw new RuntimeException("物品出库数据出现出库数量为空或其他问题");
        }
        return AjaxResult.success("新增成功");
    }

    /**
     * 查询采购出库列表
     *
     * @param ryPurchaseOut 采购出库
     * @return 采购出库
     */
    @Override
    public List<RyPurchaseOut> selectRyPurchaseOutList(RyPurchaseOut ryPurchaseOut)
    {
        return ryPurchaseOutMapper.selectRyPurchaseOutList(ryPurchaseOut);
    }

    /**
     * 查询单据主表及子表信息
     *
     * @param id 单据主表主键
     * @return 单据主表及子表信息
     */
    public DepotHeadItem selectRyDepotDetailByDepotId(Long id){
        DepotHeadItem depotHeadItem = new DepotHeadItem();
        RyPurchaseOut ryPurchaseOut = ryPurchaseOutMapper.selectRyPurchaseOutById(id);
        //主表数据
        depotHeadItem.setId(ryPurchaseOut.getId());

        depotHeadItem.setNumber(ryPurchaseOut.getNumber());//单据号
        depotHeadItem.setContractNumber(ryPurchaseOut.getContractNumber());//采购合同号
        depotHeadItem.setProjectCode(ryPurchaseOut.getProjectCode());
        depotHeadItem.setProjectName(ryPurchaseOut.getProjectName());

        depotHeadItem.setCreator(ryPurchaseOut.getCreator());//操作员
        depotHeadItem.setOperName(ryPurchaseOut.getOperName());//操作员名称

        depotHeadItem.setCreateTime(ryPurchaseOut.getCreateTime());
        depotHeadItem.setOperTime(ryPurchaseOut.getOperTime());
        depotHeadItem.setFileName(ryPurchaseOut.getFileName());
        depotHeadItem.setSalesMan(ryPurchaseOut.getSalesMan());

        depotHeadItem.setLinkNumber(ryPurchaseOut.getLinkNumber());//关联订单号
        depotHeadItem.setLinkHeadId(ryPurchaseOut.getLinkHeadId());//关联订单id
        depotHeadItem.setRemark(ryPurchaseOut.getRemark());//备注

        //子表数据(这里需要根据id查询到关联的项目总清单id,也就是上面获取到的linkHeadId，然后根据项目总清单id查询子表数据)
        List<RyDepotItem> tableData = ryDepotItemMapper.selectPurchaseOutItemByDepotId(id,ryPurchaseOut.getLinkHeadId());

        depotHeadItem.setTableData(tableData);
        return depotHeadItem;
    }

    /**
     * 根据主表修改单据子表信息
     * 1.同时需要生成出库记录
     * 2.更改项目库物品当前库存数
     * 3.设置采购总清单入库数量
     */
    @Transactional
    @Override
    public AjaxResult editDepotDetail(DepotHeadItem depotHeadItem){
        //获取用户信息
        SysUser user = SecurityUtils.getLoginUser().getUser();

        //判断是否有子表数据
        List<RyDepotItem> tableData = depotHeadItem.getTableData();
        if(tableData == null || tableData.size() ==0){
            return AjaxResult.error("子表数据不存在");
        }

        //修改项目物品出库单主表信息
        RyPurchaseOut ryPurchaseOut = new RyPurchaseOut();
        ryPurchaseOut.setId(depotHeadItem.getId());//主键，用于定位修改数据
        ryPurchaseOut.setOperTime(DateUtils.getNowDate());
        ryPurchaseOut.setFileName(depotHeadItem.getFileName());
        ryPurchaseOut.setRemark(depotHeadItem.getRemark());
        //修改
        ryPurchaseOutMapper.updateRyPurchaseOut(ryPurchaseOut);

        /**
         * 首先查询项目出库单关联明细信息，保存下来后处理仓库当前数量
         * 逻辑：
         * 1.将之前新增的数据保存下来，每条数据都有operNumber代表了出库数量
         * 2.仓库中的当前数量是出库之后的数量
         * 3.在删除数据重新插入前需要将仓库中的当前数量还原为出库前的数量
         * 4.遍历保存下来的数据，在循环中还原仓库当前数量（当前数量 + operNumber,和新增逻辑相反）
         */
        List<RyDepotItem> oldData = ryDepotItemMapper.selectRyDepotItemByDepotId(depotHeadItem.getId());
        //遍历之前新增的数据，还原仓库当前数量
        for(RyDepotItem ryDepotItem : oldData){
            //获取仓库id和商品id
            Long depotId = ryDepotItem.getDepotId();
            Long inventoryId = ryDepotItem.getInventoryId();
            RyInventoryCurrentStock paramstock = new RyInventoryCurrentStock();
            paramstock.setDepotId(depotId);
            paramstock.setInventoryId(inventoryId);
            /**
             * 修改项目库中当前库存
             * 根据仓库id和商品id查询仓库当前库存记录中是否存在此物品记录，
             * 1.存在的话就对当前量进行修改
             * 2.不存在则不处理
             */
            //查询是否存在
            RyInventoryCurrentStock result = ryInventoryCurrentStockMapper.getCurrentStockByDepotInventId(paramstock);
            System.out.println("--> result:"+result);

            //创建参数对象
            RyInventoryCurrentStock param = new RyInventoryCurrentStock();
            if(result != null) {//存在此数据，执行修改
                //计算需要更改的数量
                //获取原库存数
                Double oldNum = result.getCurrentNumber();
                //获取出库数量
                Double outNum = ryDepotItem.getOperNumber();
                //需要更改的数量
                Double updateNum = oldNum + outNum;
                param.setCurrentNumber(updateNum);

                //执行修改语句，根据id修改
                param.setId(result.getId());
                ryInventoryCurrentStockMapper.updateRyInventoryCurrentStock(param);
            }
        }

        //将子表数据先删除，根据主表id删除
        ryDepotItemMapper.deleteDepotItemByHeadId(depotHeadItem.getId());

        /**
         * 统计参数，用于统计明细出库数量
         * 如果totalInNum > 0 存在出库明细，则不需处理
         * 如果totalInNum <= 0 说明明细数据因为条件问题一条都没有出库，
         * 这时就主动抛出错误，使得事务生效，防止主表信息插入而明细表没有数据
         *
         */
        int totalInNum = 0;

        /**
         * 遍历明细数据，更新单据明细数据
         * 1.生成相应出库记录
         * 2.更改项目库物品当前库存数
         */
        for(RyDepotItem ryDepotItem : tableData){

            ryDepotItem.setHeaderId(ryPurchaseOut.getId());//设置刚生成的项目物品出库单id
            ryDepotItem.setHeaderType("1");//1代表出库数据
            ryDepotItem.setOperTime(new Date());
            ryDepotItem.setUpdateTime(new Date());

            //如果总入库数量为0或是为null,或是操作数量operNumber为0或者为null，则跳过此次循环，不进行出库操作
            if(ryDepotItem.getOperNumber() == null || ryDepotItem.getOperNumber() == 0){
                continue;
            }

            //如果出库仓库不存在，则跳过此次循环，不进行出库操作
            if(ryDepotItem.getDepotId() == null){
                continue;
            }

            //获取仓库id和商品id
            Long depotId = ryDepotItem.getDepotId();
            Long inventoryId = ryDepotItem.getInventoryId();
            RyInventoryCurrentStock paramstock = new RyInventoryCurrentStock();
            paramstock.setDepotId(depotId);
            paramstock.setInventoryId(inventoryId);

            //根据depotId和InventoryId查询出当前库存信息
            RyInventoryCurrentStock result = ryInventoryCurrentStockMapper.getCurrentStockByDepotInventId(paramstock);
            System.out.println("--> result:"+result);

            //创建参数对象
            RyInventoryCurrentStock param = new RyInventoryCurrentStock();
            //计算需要更改的总库数量
            //获取原库存数
            Double oldNum = result.getCurrentNumber();
            //获取新出库数量
            Double outNum = ryDepotItem.getOperNumber();
            //需要更改的数量
            Double updateNum = oldNum - outNum;
            param.setCurrentNumber(updateNum);

            //执行修改语句，修改库存数量，根据id修改
            param.setId(result.getId());
            ryInventoryCurrentStockMapper.updateRyInventoryCurrentStock(param);

            //执行明细新增
            ryDepotItemMapper.insertRyDepotItem(ryDepotItem);
            totalInNum += 1;
        }

        //如果统计结果小于等于0,则主动抛出异常
        if(totalInNum <= 0){
            System.out.println("应主动抛出异常,稍后完善");
        }

        return AjaxResult.success("出库成功");
    }

    /**
     * --采购出库
     * 单条数据出库
     */
    @Transactional
    @Override
    public AjaxResult oneOutDetail(RyDepotDetail ryDepotDetail){
        //获取用户信息
        SysUser user = SecurityUtils.getLoginUser().getUser();

        //如果总入库数量为0或是为null,或是操作数量operNumber为0或者为null，则跳过此次循环，不进行出库操作
        if(ryDepotDetail.getInNum() == null || ryDepotDetail.getInNum() == 0 || ryDepotDetail.getOperNumber() == null || ryDepotDetail.getOperNumber() == 0){
            return AjaxResult.error("总入库数量或出库数量为空");
        }

        //如果出库仓库不存在，则跳过此次循环，不进行入库操作
        if(ryDepotDetail.getOutDepotId() == null){
            return AjaxResult.error("出库仓库不存在");
        }

        //获取仓库id和商品id
        Long depotId = ryDepotDetail.getOutDepotId();
        Long inventoryId = ryDepotDetail.getInventoryId();
        RyInventoryCurrentStock paramstock = new RyInventoryCurrentStock();
        paramstock.setDepotId(depotId);
        paramstock.setInventoryId(inventoryId);
        //根据depotId和InventoryId查询出当前库存信息
        RyInventoryCurrentStock result = ryInventoryCurrentStockMapper.getCurrentStockByDepotInventId(paramstock);
        System.out.println("--> result:"+result);

        //创建参数对象
        RyInventoryCurrentStock param = new RyInventoryCurrentStock();
        //计算需要更改的总库数量
        //获取原库存数
        Double oldNum = result.getCurrentNumber();
        //获取新出库数量
        Double outNum = ryDepotDetail.getOperNumber();
        //需要更改的数量
        Double updateNum = oldNum - outNum;
        param.setCurrentNumber(updateNum);

        //执行修改语句，修改库存数量，根据id修改
        param.setId(result.getId());
        ryInventoryCurrentStockMapper.updateRyInventoryCurrentStock(param);

        //出库记录新增
        OutRyDepotItem outRyDepotItem = new OutRyDepotItem();
        outRyDepotItem.setInventoryId(inventoryId);
        outRyDepotItem.setDepotId(depotId);
        outRyDepotItem.setOperNumber(ryDepotDetail.getOperNumber());
        outRyDepotItem.setOperTime(DateUtils.getNowDate());
        outRyDepotItem.setOperMan(user.getUserId());
        outRyDepotItem.setPurchaseOutId(ryDepotDetail.getPurchaseOutId());//设置项目出库单id
        outRyDepotItem.setHeaderType("1");//1代表出库
        //新增
        outRyDepotItemMapper.insertOutRyDepotItem(outRyDepotItem);

        //修改采购总清单明细表中总出库数量（已出库数量+本次出库操作数量）
        ryDepotDetail.setOutNum(ryDepotDetail.getHavaOutNum() + ryDepotDetail.getOperNumber());
        ryDepotDetailMapper.updateRyDepotDetail(ryDepotDetail);
        return AjaxResult.success("出库成功");
    }

    public List<RyDepotItem> selectItemForOutByDepotId(ParamBean paramBean){
        return ryDepotItemMapper.selectItemForOutByDepotId(paramBean);
    }

    /**
     * 新增采购出库
     *
     * @param ryPurchaseOut 采购出库
     * @return 结果
     */
    @Override
    public int insertRyPurchaseOut(RyPurchaseOut ryPurchaseOut)
    {
        ryPurchaseOut.setCreateTime(DateUtils.getNowDate());
        return ryPurchaseOutMapper.insertRyPurchaseOut(ryPurchaseOut);
    }

    /**
     * 修改采购出库
     *
     * @param ryPurchaseOut 采购出库
     * @return 结果
     */
    @Override
    public int updateRyPurchaseOut(RyPurchaseOut ryPurchaseOut)
    {
        return ryPurchaseOutMapper.updateRyPurchaseOut(ryPurchaseOut);
    }

    /**
     * 批量删除采购出库
     *
     * @param ids 需要删除的采购出库主键
     * @return 结果
     */
    @Override
    public int deleteRyPurchaseOutByIds(Long[] ids)
    {
        return ryPurchaseOutMapper.deleteRyPurchaseOutByIds(ids);
    }

    /**
     * 删除采购出库信息
     *
     * @param id 采购出库主键
     * @return 结果
     */
    @Override
    public int deleteRyPurchaseOutById(Long id)
    {
        return ryPurchaseOutMapper.deleteRyPurchaseOutById(id);
    }
}
